package controlGraph;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


/**
 * @author Administrator
 * This is the object which will be the value for the store which maintains all the information
 * This object is a accumulation of 
 * 1. isArray element which says if the element is a variable or an array
 * 2. value - contains the value of the array of element , if it is a array else just one element
 * 3. ref - similar to value it has the each dimension length of array else null
 * 4. absInt - contains the abstractInt value for each variable
 * 5. contains the axiomArray of related variable in leftExp position
 */
public class StoreValue {
	private boolean isArray;
	private int ref;
	private Expression value;
	
	//Shouldn't be called
	public StoreValue(){
		this.isArray = false;
		this.value = null;
		this.ref = 0;
	}
	
	public StoreValue( int ref, Expression values){
		
		if(ref == 0){
			this.isArray = false;
			
			//If the assigned entity in a value
			if(values instanceof LValueInt){
				this.value = new LValueInt(values);
			}

			//If the assigned entity is a variable
			if(values instanceof Variable){
				Variable temp = (Variable) values;
				//getting the value expression for the corresponding variable
				StoreValue valueObject = Statement.zigma.getStoreValue(temp.getVariable());
				
				//If the variable is never declared !!!
				if(valueObject == null){
					System.out.println("Compiler error: No Variable "+temp.getVariable()+" defined");
					System.exit(1);
				}
				
				Expression e = valueObject.getExpression();
				if(e instanceof LValueInt){
					//The argument is same as e
					this.value = new LValueInt(Statement.zigma.getStoreValue(temp.getVariable()).getExpression());
				}
				if(e instanceof UndefinedExpression){
					this.value = UndefinedExpression.getInstance();
				}
				
				if(!((e instanceof LValueInt) || (e instanceof UndefinedExpression))){
					System.out.println("Error : The stored Expression for the variable "+temp.getVariable()+"  doesn't have a LValueInt stored");
					System.exit(1);
				}
			}
			
			//If the assigned entitiy is a Array Reference
			if(values instanceof ArrayRef){
				ArrayRef temp = (ArrayRef) values;
				String variable_name = temp.getVariable();
				Expression index = temp.getIndexExpression();
				ArrayList<String> empty = new ArrayList<String>();
				
				//Called SAT solver
				if(Statement.getResult(variable_name, index,empty )){
					//GEt the array
					Expression e = Statement.zigma.getStoreValue(temp.getVariable()).getExpression();
					
					//Check if a array
					if(!(e instanceof ArrayLitExpression) ){
						System.out.println("Trying to array access a non-array");
					}
					
					//Determine the Index
					if(index instanceof Variable){
						index = new LValueInt(Statement.zigma.getLValueInt(index));
					}
					if(index instanceof LValueInt){
						//nothing to change
					}
					
					//Get the corresponding expression
					Expression resultant = ((ArrayLitExpression)e).getExpressionAtIndex(((LValueInt)index).getValue());
					
					//Check if the RValue is undefined or defined to LValueInt
					if(resultant instanceof UndefinedExpression){
						this.value = resultant;
					}
					if(resultant instanceof LValueInt){
						this.value = new LValueInt(resultant);
					}
					System.out.println("The array access at "+ index+" in "+  variable_name);
				}else{
					System.out.println("This array reference is Unsatisfiable");
					System.exit(1);
				}
			}
			
			//if the variable is undeclared 
			if(values instanceof UndefinedExpression){
				this.value = values;
			}
			
		}//end if (ref==0)
		else//elseif (ref==0)
		{
			this.isArray = true;
			if(values instanceof UndefinedExpression){
				ArrayList<Expression> temp = new ArrayList<Expression>();
				for(int j=0;j<ref;++j){
					temp.add(UndefinedExpression.getInstance());
				}
				Expression[] passIt = (Expression[])temp.toArray(new Expression[temp.size()]);
				this.value = new ArrayLitExpression(passIt);
			}
			else{ //Properly defined i.e. values is an instance of ArrayLitExpression
				this.value = values;
			}
		}
		this.ref = ref;
	}
	
	public boolean getArrayType(){
		return this.isArray;
	}
	
	public int getRef(){
		return this.ref;
	}
	
	public Expression getExpression(){
		return this.value;
	}
}